package com.player.rest.resource;

import java.net.URI;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.Status;

import org.json.JSONException;

import com.player.dao.DAOLocator;
import com.player.dao.PlayerDAO;
import com.player.dao.RankingDAO;
import com.player.entity.Player;
import com.player.entity.RankinglistType;
import com.player.rest.exception.FaultInfo;
import com.player.rest.exception.PropertyAlreadyExistsException;
import com.player.rest.exception.ServiceErrorCode;
import com.player.rest.exception.ServiceException;
import com.player.rest.util.InputValidator;
import com.player.rest.util.ResponseConverter;
import com.player.rest.util.ValidationResult;

@Path("players")
public class PlayerResource {

	public static final String FORM_PARAM_PLAYERNAME = "playername";
	public static final String FORM_PARAM_EMAIL = "email";
	public static final String FORM_PARAM_RANKINGLIST = "rankinglist";

	@Context
	UriInfo uriInfo;

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public String getPlayers() throws JSONException {
		List<Player> players = DAOLocator.getPlayerDAO().getAll();
		return ResponseConverter.toJSONPlayer(players);
	}

	@GET
	@Path("{id}")
	@Produces(MediaType.APPLICATION_JSON)
	public String getPlayer(@PathParam("id") long id) throws JSONException {
		Player player = DAOLocator.getPlayerDAO().get(id);
		if (player == null) {
			FaultInfo faultInfo = new FaultInfo(ServiceErrorCode.RESOURCE_NOT_FOUND, "Player with id=" + id
					+ " not found.");
			throw new ServiceException(Status.NOT_FOUND, faultInfo);
		} else {
			return ResponseConverter.toJSONPlayer(player).toString();
		}
	}

	// FIXME remove? find a spot to do auth for rest calls
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	@Path("/playernameSecure")
	public String getPlayernameSecure(@Context SecurityContext sc, @PathParam(FORM_PARAM_PLAYERNAME) String playername) {
		return playername + " - userPrincipal = " + sc.getUserPrincipal() + " - " + sc.getAuthenticationScheme()
				+ " - " + sc.isSecure() + " . ";
	}

	@POST
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response createNewPlayer(@FormParam(FORM_PARAM_EMAIL) String email,
			@FormParam(FORM_PARAM_PLAYERNAME) String playername, @FormParam(FORM_PARAM_RANKINGLIST) String rankinglist)
			throws JSONException {
		ValidationResult result = validateInput(playername, email, rankinglist);

		if (result.isValid()) {
			try {
				Player player = DAOLocator.getPlayerDAO().create(email, playername);
				DAOLocator.getRankingDAO().create(player.getId(), RankinglistType.valueOf(rankinglist));
				return Response.created(getUri(player)).header("PlayerId", player.getId()).build();
			} catch (PropertyAlreadyExistsException e) {
				if (PlayerDAO.PROP_EMAIL.equals(e.getPropertyName())) {
					result.addMessage(FORM_PARAM_EMAIL, e.getMessage());
				} else if (PlayerDAO.PROP_PLAYERNAME_NORMALIZED.equals(e.getPropertyName())) {
					result.addMessage(FORM_PARAM_PLAYERNAME, e.getMessage());
				} else if (RankingDAO.PROP_PLAYER_KEY.equals(e.getPropertyName())) {
					result.addMessage(FORM_PARAM_RANKINGLIST, e.getMessage());
				} else {
					FaultInfo faultInfo = new FaultInfo(ServiceErrorCode.RESOURCE_NOT_FOUND,
							"Resource property unknown: Player." + e.getPropertyName() + "=" + e.getPropertyValue(),
							Player.class.getSimpleName(), null);
					throw new ServiceException(Status.INTERNAL_SERVER_ERROR, faultInfo);
				}
			}
		}

		return Response.status(Status.BAD_REQUEST).entity(ResponseConverter.buildErrorJSON(result)).build();
	}

	private URI getUri(Player player) {
		return uriInfo.getAbsolutePathBuilder().path(player.getId().toString()).build();
	}

	private ValidationResult validateInput(String playername, String email, String rankinglist) {
		ValidationResult result = new ValidationResult();
		InputValidator.validateEmail(email.trim(), FORM_PARAM_EMAIL, result);
		InputValidator.validatePlayername(playername.trim(), FORM_PARAM_PLAYERNAME, result);
		InputValidator.validateRankinglist(rankinglist, FORM_PARAM_RANKINGLIST, result);
		return result;
	}
}
